package shujia.day15;
/*
    实现Runnable接口实现电影院售票
    某电影院目前正在上映贺岁大片，共有100张票，而它有3个售票窗口售票，请设计一个程序模拟该电影院售票。


    为了模拟更加真实的售票情况，我们每出售一张票之前延迟几毫秒
    问题1：我们加入延迟之后发现，出现了
            1）多个窗口售卖同一张票的情况
                CPU小小的时间片足以运行多次,线程的执行具有原子性
            2）售卖第0张票和第-1张票的情况
                线程的执行具有随机性【抢占式执行的】
          我们解释了为什么会出现这些问题，其实这个问题就是线程不安全的情况。如何判断一个程序是否存在现在安全的问题的呢？
          若下面三个前提都满足的情况下，那么这个程序就有线程安全的问题：
            a: 是否是多线程环境？是，有三个线程对象
            b: 是否有共享数据【变量】？有，tickets
            c: 是否有多条语句操作着共享数据？有
    解决线程安全问题的方案：
            synchronized关键字
            Lock锁

    synchronized关键字使用：
        1、同步代码块，将操作共享数据的代码，使用同步代码块包起来，有点像上锁的概念
            synchronized(全局唯一的对象[锁对象]){
                //操作共享数据的代码
            }

        2、同步方法
            锁对象：this

        3、同步静态方法
            锁对象：当前线程类的class文件对象



 */

class MyRunnable5 implements Runnable {
    static int tickets = 100;
    Object obj = new Object();
    int i = 0;

    @Override
    public void run() {
        while (true) {
            if (i % 2 == 0) {
                synchronized (MyRunnable5.class) {
                    if (tickets > 0) { // tickets=1
                        try {
                            // w1, w2, w3
                            Thread.sleep(20); // 阻塞
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票。。");
                    }
                }
            } else {
                sell();
            }
            i++;
        }
    }

    //静态同步方法，将synchronized加在静态方法上
    public static synchronized void sell() {
        if (tickets > 0) { // tickets=1
            try {
                // w1, w2, w3
                Thread.sleep(20); // 阻塞
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票。。");
        }
    }


    //同步方法，将synchronized加在方法
//    public synchronized void sell() {
//        if (tickets > 0) { // tickets=1
//            try {
//                // w1, w2, w3
//                Thread.sleep(20); // 阻塞
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票。。");
//        }
//    }
}

public class SellTicketDemo5 {
    public static void main(String[] args) {
        MyRunnable5 myRunnable5 = new MyRunnable5();

        Thread w1 = new Thread(myRunnable5, "窗口1");
        Thread w2 = new Thread(myRunnable5, "窗口2");
        Thread w3 = new Thread(myRunnable5, "窗口3");

        w1.start();
        w2.start();
        w3.start();
    }
}
